﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Fabrication.DataStructures;
using NUnit.Framework;

namespace Fabrication.Tests.DataStructures
{
    [TestFixture]
    public class sequence
    {
        [Test]
        public void should_throw_exception_when_calling_next_on_sequence_with_no_items()
        {
            var sequence = new Sequence<int>();
            Assert.Throws<EmptySequenceException>(() => sequence.Next());
        }

        [Test]
        public void should_only_enumerate_through_original_items_using_non_generic_enumerator()
        {
            var sequence = new Sequence<int>();
            sequence.Add(1);
            sequence.Add(5);

            var itemCount = 0;
            foreach (var item in (IEnumerable)sequence)
                itemCount++;
            
            Assert.That(itemCount, Is.EqualTo(2));
        }

        [Test]
        public void should_handle_enumerating_through_empty_sequence()
        {
            var sequence = new Sequence<int>();

            var itemCount = 0;
            foreach (var item in (IEnumerable)sequence)
                itemCount++;

            Assert.That(itemCount, Is.EqualTo(0));
        }

        [Test]
        public void should_only_enumerate_through_original_items_using_generic_enumerator()
        {
            var sequence = new Sequence<int>();
            sequence.Add(1);
            sequence.Add(5);

            var itemCount = sequence.Count();

            Assert.That(itemCount, Is.EqualTo(2));
        }

        [Test]
        public void should_return_values_in_order()
        {
            var sequence = new Sequence<int>();
            sequence.Add(1);
            sequence.Add(5);
            sequence.Add(3);

            Assert.That(sequence.Next(), Is.EqualTo(1));
            Assert.That(sequence.Next(), Is.EqualTo(5));
            Assert.That(sequence.Next(), Is.EqualTo(3));
        }

        [Test]
        public void should_loop_through_sequence_in_order()
        {
            var sequence = new Sequence<int>();
            sequence.Add(1);
            sequence.Add(5);
            sequence.Add(3);

            Assert.That(sequence.Next(), Is.EqualTo(1));
            Assert.That(sequence.Next(), Is.EqualTo(5));
            Assert.That(sequence.Next(), Is.EqualTo(3));
            Assert.That(sequence.Next(), Is.EqualTo(1));
            Assert.That(sequence.Next(), Is.EqualTo(5));
            Assert.That(sequence.Next(), Is.EqualTo(3));
        }

        [Test]
        public void should_create_with_collection_initializer()
        {
            var sequence = new Sequence<int> { 5, 4, 3 };

            Assert.That(sequence.Next(), Is.EqualTo(5));
            Assert.That(sequence.Next(), Is.EqualTo(4));
            Assert.That(sequence.Next(), Is.EqualTo(3));
        }

        [Test]
        public void should_create_with_parameters()
        {
            var sequence = new Sequence<int>(5, 4, 3);

            Assert.That(sequence.Next(), Is.EqualTo(5));
            Assert.That(sequence.Next(), Is.EqualTo(4));
            Assert.That(sequence.Next(), Is.EqualTo(3));
        }

        [Test]
        public void should_create_with_enumerable_items()
        {
            var items = new List<int> {1, 2, 3};
            var sequence = new Sequence<int>(items);

            Assert.That(sequence.Next(), Is.EqualTo(1));
            Assert.That(sequence.Next(), Is.EqualTo(2));
            Assert.That(sequence.Next(), Is.EqualTo(3));
        }

        [Test]
        public void should_handle_sequence_with_single_item()
        {
            var items = new List<int> { 1 };
            var sequence = new Sequence<int>(items);

            Assert.That(sequence.Next(), Is.EqualTo(1));
            Assert.That(sequence.Next(), Is.EqualTo(1));
        }
    }
}
